/**
 * JavaScript版本的AudioCPFSK调制器
 * 基于Python版本的mod.py实现
 */
class AudioCPFSK {
    constructor(fSample, fSpace, fMark, bitRate) {
        // 参数验证
        if (fSample % bitRate !== 0) {
            throw new Error("采样频率必须是比特率的整数倍");
        }
        if ((fSpace + fMark) % 2 !== 0) {
            throw new Error("空间频率和标记频率之和必须是偶数");
        }
        if (!(0 < fSpace && fSpace < fMark && fMark < fSample / 2)) {
            throw new Error("频率必须满足: 0 < fSpace < fMark < fSample/2");
        }

        this.fSample = fSample;
        this.fSpace = fSpace;
        this.fMark = fMark;
        this.fCenter = (fSpace + fMark) / 2;
        this.fDelta = (fMark - fSpace) / 2;
        this.bitRate = bitRate;
        this.nPerBit = Math.floor(fSample / bitRate); // 每个比特的采样点数
    }

    /**
     * 对比特序列进行CPFSK调制
     * @param {boolean[]} bits - 比特序列 (true表示1/mark频率, false表示0/space频率)
     * @param {number} amplitude - 信号幅度
     * @param {number} attackBits - 前导载波的比特数
     * @returns {Float32Array} 调制后的音频信号
     */
    modulate(bits, amplitude = 1.0, attackBits = 4) {
        if (!bits || bits.length === 0) {
            return new Float32Array(0);
        }

        // 计算前导载波的采样点数
        const preambleSamples = attackBits * this.nPerBit;
        
        // 总采样点数（包括前导）
        const dataSamples = bits.length * this.nPerBit;
        const totalSamples = preambleSamples + dataSamples;
        const signal = new Float32Array(totalSamples);
        
        // 相位累积器，确保相位连续
        let phaseAccumulator = 0.0;
        
        // 1. 生成前导载波信号（使用中心频率）
        const preamblePhaseIncrement = 2 * Math.PI * this.fCenter / this.fSample;
        for (let i = 0; i < preambleSamples; i++) {
            signal[i] = amplitude * Math.cos(phaseAccumulator);
            phaseAccumulator += preamblePhaseIncrement;
        }
        
        // 保持相位连续性
        phaseAccumulator = phaseAccumulator % (2 * Math.PI);
        
        // 2. 生成数据信号
        for (let i = 0; i < bits.length; i++) {
            // 根据比特值选择频率
            const freq = bits[i] ? this.fMark : this.fSpace;
            
            // 计算当前比特周期内的相位增量
            const phaseIncrement = 2 * Math.PI * freq / this.fSample;
            
            // 当前比特的采样点范围（考虑前导偏移）
            const startIdx = preambleSamples + i * this.nPerBit;
            
            // 生成当前比特周期的信号
            for (let j = 0; j < this.nPerBit; j++) {
                signal[startIdx + j] = amplitude * Math.cos(phaseAccumulator);
                phaseAccumulator += phaseIncrement;
            }
                
            // 保持相位在合理范围内，避免数值溢出
            phaseAccumulator = phaseAccumulator % (2 * Math.PI);
        }
        
        return signal;
    }
}

/**
 * 计算字节序列的校验和
 * @param {Uint8Array} bytes - 字节序列
 * @returns {number} 校验和值（0-255）
 */
function calculateChecksum(bytes) {
    let sum = 0;
    for (const byte of bytes) {
        sum += byte;
    }
    return sum & 0xFF; // 保持在0-255范围内
}

/**
 * 文本转比特序列（包含校验和）
 * @param {string} text - 输入文本
 * @param {Uint8Array} startBytes - 起始字节序列
 * @param {Uint8Array} endBytes - 结束字节序列
 * @returns {boolean[]} 比特序列
 */
function textToBits(text, startBytes = new Uint8Array([0x01, 0x02]), endBytes = new Uint8Array([0x03, 0x04])) {
    // 将文本编码为UTF-8字节
    const encoder = new TextEncoder();
    const textBytes = encoder.encode(text);
    
    // 计算文本的校验和
    const checksum = calculateChecksum(textBytes);
    const checksumByte = new Uint8Array([checksum]);
    
    // 更新校验和显示
    document.getElementById('checksum').value = `0x${checksum.toString(16).padStart(2, '0').toUpperCase()}`;
    
    // 组合字节序列：起始 + 文本 + 校验和 + 结束
    const totalBytes = new Uint8Array(startBytes.length + textBytes.length + checksumByte.length + endBytes.length);
    totalBytes.set(startBytes, 0);
    totalBytes.set(textBytes, startBytes.length);
    totalBytes.set(checksumByte, startBytes.length + textBytes.length);
    totalBytes.set(endBytes, startBytes.length + textBytes.length + checksumByte.length);
    
    // 转换为比特序列
    const bits = [];
    for (const byte of totalBytes) {
        for (let i = 7; i >= 0; i--) {
            bits.push((byte >> i) & 1 ? true : false);
        }
    }
    
    return bits;
}

/**
 * 创建WAV文件的ArrayBuffer
 * @param {Float32Array} audioData - 音频数据
 * @param {number} sampleRate - 采样率
 * @returns {ArrayBuffer} WAV文件的ArrayBuffer
 */
function createWavFile(audioData, sampleRate) {
    const length = audioData.length;
    const arrayBuffer = new ArrayBuffer(44 + length * 2);
    const view = new DataView(arrayBuffer);
    
    // WAV文件头
    const writeString = (offset, string) => {
        for (let i = 0; i < string.length; i++) {
            view.setUint8(offset + i, string.charCodeAt(i));
        }
    };
    
    writeString(0, 'RIFF');
    view.setUint32(4, 36 + length * 2, true); // 文件大小
    writeString(8, 'WAVE');
    writeString(12, 'fmt ');
    view.setUint32(16, 16, true); // fmt chunk大小
    view.setUint16(20, 1, true); // 音频格式 (PCM)
    view.setUint16(22, 1, true); // 声道数
    view.setUint32(24, sampleRate, true); // 采样率
    view.setUint32(28, sampleRate * 2, true); // 字节率
    view.setUint16(32, 2, true); // 块对齐
    view.setUint16(34, 16, true); // 位深度
    writeString(36, 'data');
    view.setUint32(40, length * 2, true); // 数据大小
    
    // 写入音频数据 (转换为16位PCM)
    const offset = 44;
    for (let i = 0; i < length; i++) {
        const sample = Math.max(-1, Math.min(1, audioData[i]));
        view.setInt16(offset + i * 2, sample * 0x7FFF, true);
    }
    
    return arrayBuffer;
}

/**
 * 显示状态消息
 * @param {string} message - 消息内容
 * @param {string} type - 消息类型 ('info', 'success', 'error')
 */
function showStatus(message, type = 'info') {
    const statusDiv = document.getElementById('status');
    statusDiv.textContent = message;
    statusDiv.className = `status-${type}`;
}

// 全局变量
let audioContext = null;
let audioBuffer = null;
let audioSource = null;
let generatedAudioData = null;
let isLooping = false;

// 初始化音频上下文
function initAudioContext() {
    if (!audioContext) {
        audioContext = new (window.AudioContext || window.webkitAudioContext)();
    }
    return audioContext;
}

// 生成音频
function generateAudio() {
    try {
        // 获取参数
        const fSample = parseInt(document.getElementById('fSample').value);
        const fSpace = parseInt(document.getElementById('fSpace').value);
        const fMark = parseInt(document.getElementById('fMark').value);
        const bitRate = parseInt(document.getElementById('bitRate').value);
        const amplitude = parseFloat(document.getElementById('amplitude').value);
        const attackBits = parseInt(document.getElementById('attackBits').value);
        const text = document.getElementById('textInput').value;

        if (!text.trim()) {
            showStatus('请输入要转换的文本', 'error');
            return;
        }

        showStatus('正在生成音频...', 'info');

        // 创建调制器
        const modulator = new AudioCPFSK(fSample, fSpace, fMark, bitRate);
        
        // 转换文本为比特序列
        const bits = textToBits(text);
        
        // 调制
        generatedAudioData = modulator.modulate(bits, amplitude, attackBits);
        
        // 创建音频缓冲区
        const context = initAudioContext();
        audioBuffer = context.createBuffer(1, generatedAudioData.length, fSample);
        audioBuffer.copyToChannel(generatedAudioData, 0);
        
        // 启用播放和下载按钮
        document.getElementById('playButton').disabled = false;
        document.getElementById('loopButton').disabled = false;
        document.getElementById('downloadButton').disabled = false;
        
        showStatus(`音频生成成功！时长: ${(generatedAudioData.length / fSample).toFixed(2)}秒`, 'success');
        
    } catch (error) {
        showStatus(`生成失败: ${error.message}`, 'error');
        console.error('Generate audio error:', error);
    }
}

// 播放音频
function playAudio() {
    try {
        if (!audioBuffer) {
            showStatus('请先生成音频', 'error');
            return;
        }

        const context = initAudioContext();
        
        // 停止之前的播放
        if (audioSource) {
            audioSource.stop();
        }
        
        // 创建新的音频源
        audioSource = context.createBufferSource();
        audioSource.buffer = audioBuffer;
        audioSource.connect(context.destination);
        
        // 播放结束回调
        audioSource.onended = () => {
            if (isLooping && audioBuffer) {
                // 如果是循环模式且还有音频缓冲区，继续播放
                playAudio();
            } else {
                // 正常结束播放
                document.getElementById('playButton').disabled = false;
                document.getElementById('loopButton').disabled = false;
                document.getElementById('stopButton').disabled = true;
                isLooping = false;
                showStatus('播放完成', 'success');
            }
        };
        
        audioSource.start();
        
        document.getElementById('playButton').disabled = true;
        document.getElementById('loopButton').disabled = true;
        document.getElementById('stopButton').disabled = false;
        
        if (isLooping) {
            showStatus('正在循环播放...', 'info');
        } else {
            showStatus('正在播放...', 'info');
        }
        
    } catch (error) {
        showStatus(`播放失败: ${error.message}`, 'error');
        console.error('Play audio error:', error);
    }
}

// 停止播放
function stopAudio() {
    try {
        if (audioSource) {
            audioSource.stop();
            audioSource = null;
        }
        
        isLooping = false;
        document.getElementById('playButton').disabled = false;
        document.getElementById('loopButton').disabled = false;
        document.getElementById('stopButton').disabled = true;
        showStatus('播放已停止', 'info');
        
    } catch (error) {
        showStatus(`停止失败: ${error.message}`, 'error');
        console.error('Stop audio error:', error);
    }
}

// 下载WAV文件
function downloadWav() {
    try {
        if (!generatedAudioData) {
            showStatus('请先生成音频', 'error');
            return;
        }

        const fSample = parseInt(document.getElementById('fSample').value);
        const wavArrayBuffer = createWavFile(generatedAudioData, fSample);
        
        const blob = new Blob([wavArrayBuffer], { type: 'audio/wav' });
        const url = URL.createObjectURL(blob);
        
        const a = document.createElement('a');
        a.href = url;
        a.download = 'afsk_modulated.wav';
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
        
        showStatus('WAV文件下载成功', 'success');
        
    } catch (error) {
        showStatus(`下载失败: ${error.message}`, 'error');
        console.error('Download WAV error:', error);
    }
}

/**
 * 更新校验和显示
 */
function updateChecksum() {
    const text = document.getElementById('textInput').value;
    if (text.trim()) {
        const encoder = new TextEncoder();
        const textBytes = encoder.encode(text);
        const checksum = calculateChecksum(textBytes);
        document.getElementById('checksum').value = `0x${checksum.toString(16).padStart(2, '0').toUpperCase()}`;
    } else {
        document.getElementById('checksum').value = '0x00';
    }
}

// 参数验证
function validateParameters() {
    const fSample = parseInt(document.getElementById('fSample').value);
    const fSpace = parseInt(document.getElementById('fSpace').value);
    const fMark = parseInt(document.getElementById('fMark').value);
    const bitRate = parseInt(document.getElementById('bitRate').value);

    let isValid = true;
    let errorMsg = '';

    if (fSample % bitRate !== 0) {
        isValid = false;
        errorMsg = '采样频率必须是比特率的整数倍';
    } else if (fSpace >= fMark) {
        isValid = false;
        errorMsg = '标记频率必须大于空间频率';
    } else if (fMark >= fSample / 2) {
        isValid = false;
        errorMsg = '标记频率不能超过采样频率的一半';
    }

    if (!isValid) {
        showStatus(errorMsg, 'error');
        document.getElementById('generateButton').disabled = true;
    } else {
        document.getElementById('generateButton').disabled = false;
        showStatus('参数验证通过', 'success');
    }
}

// 循环播放
function loopAudio() {
    try {
        if (!audioBuffer) {
            showStatus('请先生成音频', 'error');
            return;
        }

        isLooping = true;
        playAudio();
        
    } catch (error) {
        showStatus(`循环播放失败: ${error.message}`, 'error');
        console.error('Loop audio error:', error);
    }
}

// 事件监听器
document.addEventListener('DOMContentLoaded', function() {
    // 按钮事件
    document.getElementById('generateButton').addEventListener('click', generateAudio);
    document.getElementById('playButton').addEventListener('click', playAudio);
    document.getElementById('loopButton').addEventListener('click', loopAudio);
    document.getElementById('stopButton').addEventListener('click', stopAudio);
    document.getElementById('downloadButton').addEventListener('click', downloadWav);
    
    // 参数变化时验证
    const paramInputs = ['fSample', 'fSpace', 'fMark', 'bitRate'];
    paramInputs.forEach(id => {
        document.getElementById(id).addEventListener('input', validateParameters);
    });
    
    // 文本输入变化时更新校验和
    document.getElementById('textInput').addEventListener('input', updateChecksum);
    
    // 初始验证
    validateParameters();
    
    // 设置示例文本
    document.getElementById('textInput').value = "Hello, this is a test!\nNice to meet you!";
    
    // 初始化校验和
    updateChecksum();
    
    showStatus('就绪，请设置参数并输入文本', 'info');
});